package com.ruoyi.eqmonitor.controller;

import breeze.framework.word.WordToolkit;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.eqmonitor.dispose.dtos.ReportAVo;
import com.ruoyi.eqmonitor.dispose.service.ExteriorSiteMonitorDataService;
import com.ruoyi.eqmonitor.domain.OptInterceptingWellRenovate;
import com.ruoyi.eqmonitor.vo.ReportCVo;
import com.ruoyi.eqmonitor.dtos.WordReportDto;
import com.ruoyi.eqmonitor.service.IOptDeviceAlarmService;
import com.ruoyi.eqmonitor.service.impl.OptInterceptingWellRenovateServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

@Slf4j
@Api(tags = "总结报告")
@RestController
@RequestMapping("/wordReport")
public class WordReportController {

    @Resource
    private ExteriorSiteMonitorDataService siteMonitorDataService;
    @Resource
    private OptInterceptingWellRenovateServiceImpl optInterceptingWellRenovateService;
    @Resource
    private IOptDeviceAlarmService optDeviceAlarmService;

    @ApiOperation("生成报告")
    @PostMapping("/getWholeText")
    public String getWholeText(@RequestBody WordReportDto dto){
        String targetPath = report(dto);
        WordToolkit.World2007Plus world2007Plus = WordToolkit.toolkit.new World2007Plus(targetPath);
        return WordToolkit.getWholeText(world2007Plus);
    }

    @ApiOperation("导出报告")
    @Log(title = "导出报告", businessType = BusinessType.EXPORT)
    @PostMapping(value = "/downloadWord")
    public ResponseEntity<ByteArrayResource> downloadWord(WordReportDto dto) throws IOException {
        String targetPath = report(dto);
        File file = new File(targetPath);
        Path path = Paths.get(file.getAbsolutePath());
        ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(path));

        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION,
                "attachment; filename=" + file.getName());
        headers.add(HttpHeaders.CONTENT_TYPE, "application/octet-stream");
        headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(file.length()));
        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(file.length())
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(resource);
    }

    /**
     * 生成报告
     */
    public String report(WordReportDto dto){
        String dateTimeString = dto.getDateTimeString();
        SimpleDateFormat sdf0 = new SimpleDateFormat("yyyy-MM");
        try {
            Date dateTime = sdf0.parse(dateTimeString);
            dto.setDateTime(dateTime);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        //生成文件路径及文件名
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月");
        String targetPath = "/breeze/sewage/word/"
                + dto.getAreaName()
                + sdf.format(dto.getDateTime());
        int state = dto.getState();
        if (state == 0){
            targetPath += "月度报告(环比).docx";
        }else if (state == 1){
            targetPath += "月度报告(同比).docx";
        }else {
            targetPath += "年度报告.docx";
        }
        File file = new File(targetPath);
        //判断文件是否存在
        if (!file.exists()) {
            Map<String, Object> maps = new HashMap<String,Object>();
            maps.put("${乡镇/街道}$",dto.getAreaName());
            Date dateTime = dto.getDateTime();
            maps.put("${日期}$",sdf.format(dateTime));
            Calendar c = Calendar.getInstance();
            c.setTime(dateTime);
            maps.put("${年}$",c.get(Calendar.YEAR));
            //处理时间参数
            WordReportDto wordReportDto = disposeDate(dto);

            List<LinkedHashMap<String, Object>> list = new ArrayList<>();

            //创建线程池
            ExecutorService executor = Executors.newFixedThreadPool(4);
            List<Future<?>> futures = new ArrayList<>();
            //水质监测断面
            futures.add(executor.submit(() -> {
                try {
                    ReportAVo data = siteMonitorDataService.report(wordReportDto);
                    maps.put("${A1}$", data.getA1());
                    maps.put("${A2}$", data.getA2());
                    maps.put("${A3}$", data.getA3());
                    maps.put("${A4}$", data.getA4());
                    maps.put("${A5}$", data.getA5());
                    maps.put("${A6}$", data.getA6());
                    maps.put("${A7}$", data.getA7());
                    maps.put("${A8}$", data.getA8());
                    list.add(new LinkedHashMap<String, Object>() {{
                        put("项目", "监测断面达到Ⅲ类水及以上的数量");
                        put("上月", data.getLastA1());
                        put("本月", data.getA1());
                    }});
                    list.add(new LinkedHashMap<String, Object>() {{
                        put("项目", "达标率");
                        put("上月", "总数" + data.getZA1() + "，达标率" + data.getLastA2() + "%");
                        put("本月", "总数" + data.getZA2() + "，达标率" + data.getA2() + "%");
                    }});
                } catch (Exception e) {
                    log.error("总结报告-->查询水质监测断面报告相关数据失败");
                    e.printStackTrace();
                }
            }));

            //溢流井整治
            futures.add(executor.submit(() -> {
                try {
                    LambdaQueryWrapper<OptInterceptingWellRenovate> lqw = new LambdaQueryWrapper<>();
                    lqw.eq(OptInterceptingWellRenovate::getAreaName, dto.getAreaName());
                    OptInterceptingWellRenovate data = optInterceptingWellRenovateService.getOne(lqw);

                    maps.put("${B1}$", data.getAcceptance());
                    maps.put("${B2}$", data.getZzxh());
                    list.add(new LinkedHashMap<String, Object>() {{
                        put("项目", "溢流井");
                        put("上月", "已整治" + data.getAcceptance() + "，总数" + data.getRenovate());
                        put("本月", "已整治" + data.getAcceptance() + "，总数" + data.getRenovate());
                    }});
                } catch (Exception e) {
                    log.error("总结报告-->查询溢流井整治报告相关数据失败");
                    e.printStackTrace();
                }
            }));

            //碧水指数、畅水指数
            futures.add(executor.submit(() -> {
                try {
                    ReportCVo data = optDeviceAlarmService.report(dto);
                    maps.put("${C1}$", data.getC1());
                    maps.put("${C2}$", data.getC2());
                    maps.put("${C3}$", data.getC3());
                    maps.put("${C4}$", data.getC4());
                    maps.put("${C5}$", data.getC5());
                    maps.put("${C6}$", data.getC6());
                    maps.put("${C7}$", data.getC7());
                    maps.put("${C8}$", data.getC8());
                    maps.put("${C9}$", data.getC9());
                    maps.put("${C10}$", data.getC10());
                    maps.put("${C11}$", data.getC11());
                    maps.put("${C12}$", data.getC12());
                    list.add(new LinkedHashMap<String, Object>() {{
                        put("项目", "碧水指数排名");
                        put("上月", "第" + data.getLastC1());
                        put("本月", "第" + data.getC1());
                    }});
                    list.add(new LinkedHashMap<String, Object>() {{
                        put("项目", "畅水指数排名");
                        put("上月", "第" + data.getLastC3());
                        put("本月", "第" + data.getC3());
                    }});
                } catch (Exception e) {
                    log.error("总结报告-->查询碧水指数、畅水指数报告相关数据失败");
                    e.printStackTrace();
                }
            }));

            /**
             * 事件目前为假数据
             * 事件还需计算评分 --> 碧水${C11}$分+畅水${C12}$分+事件1.67分（4*2+2*1）/6）=5.67分
             * 总结时需要用上，需要（本月、上月、去年同月、本年、去年）评分，
             * 按筛选参数返回相应需要的评分
             */
            //事件
            futures.add(executor.submit(() -> {
                try {
                    List<Integer> data = new ArrayList<>();
                    for (int i = 0; i < 10; i++) {
                        data.add(i);
                    }
                    maps.put("${D1}$", 1);
                    maps.put("${D2}$", 2);
                    maps.put("${D3}$", 3);
                    maps.put("${D4}$", 4);
                    maps.put("${D5}$", 5);
                    maps.put("${D6}$", 6);
                    maps.put("${D7}$", 7);
                    maps.put("${D8}$", 8);
                    maps.put("${D9}$", 9);
                    maps.put("${D10}$", 10);
                    list.add(new LinkedHashMap<String, Object>() {{
                        put("项目", "事件派单");
                        put("上月", 5);
                        put("本月", 6);
                    }});
                    list.add(new LinkedHashMap<String, Object>() {{
                        put("项目", "事件回复");
                        put("上月", 5);
                        put("本月", 6);
                    }});
                    list.add(new LinkedHashMap<String, Object>() {{
                        put("项目", "事件整改");
                        put("上月", 4);
                        put("本月", 4);
                    }});
                } catch (Exception e) {
                    log.error("总结报告-->查询事件报告相关数据失败");
                    e.printStackTrace();
                }
            }));

            try {
                //等待所有任务执行完成
                for (Future<?> future : futures) {
                    future.get();
                }
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            } finally {
                // 关闭线程池
                executor.shutdown();
            }

            //总
            maps.put("${考核分/月}$",1);
            maps.put("${排名/月}$",2);
            //(上升X名/下降X名/排名无变化)
            maps.put("${较上月}$","排名无变化");
            //(总体情况优秀(≥8.5分)/总体情况良好(≥7分,＜8.5分)/总体情况合格(≥6分,＜7分)/总体情况较差(＜6分)。注：若排名为6-10名，额外增加“仍需进一步加强治水工作”)
            maps.put("${评价/月}$","总体情况优秀");
            //(上升X名/下降X名/排名无变化)
            maps.put("${较去年同期}$","排名无变化");
            maps.put("${考核分/年}$",6);
            maps.put("${排名/年}$",7);
            //(上升X名/下降X名/排名无变化)
            maps.put("${较去年}$","排名无变化");
            //总体情况优秀(≥8.5分)/总体情况良好(≥7分,＜8.5分)/总体情况合格(≥6分,＜7分)/总体情况较差(＜6分)。注：若排名为6-10名，额外增加“仍需进一步加强治水工作”)
            maps.put("${评价/年}$","总体情况优秀");
            list.add(new LinkedHashMap<String, Object>() {{
                put("项目", "10个乡镇街道总排名");
                put("上月", "第" + 4);
                put("本月", "第" + 5);
            }});

            //表格
            maps.put("$e{基础数据表格}$", list);

            //获取模板文件路径
            String localPath = "/breeze/sewage/word/";
            if (state == 0){
                localPath += "智慧化治水监管系统月度报告（环比）-模板.docx";
            }else if (state == 1){
                localPath += "智慧化治水监管系统月度报告（同比）-模板.docx";
            }else {
                localPath += "智慧化治水监管系统年度总结-模板.docx";
            }
            WordToolkit.World2007Plus word2 = WordToolkit.toolkit.new World2007Plus(localPath);
            for (String key : maps.keySet()) {
                if(key.startsWith("${") || key.startsWith("$v{")) {
                    WordToolkit.replaceVarTag(word2,key,maps.get(key),"edit");
                }else if(key.startsWith("$e{") || key.startsWith("$each{")) {
                    WordToolkit.replaceTableEachTag(word2,key,(List<Map<String,Object>>)maps.get(key));
                }
            }
            //新增报告文档
            WordToolkit.saveTo(word2,targetPath);
        }
        return targetPath;
    }

    /**
     * 处理时间参数
     */
    private static WordReportDto disposeDate(WordReportDto dto) {
        LocalDateTime dateTime = LocalDateTime.ofInstant(dto.getDateTime().toInstant(), ZoneId.systemDefault());
        // 本月开始时间
        LocalDateTime beginDate = dateTime.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
        dto.setBeginDate(formatterDateTime(beginDate));

        // 本月结束时间
        LocalDateTime endDate = dateTime.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
        dto.setEndDate(formatterDateTime(endDate));

        // 上月开始时间
        LocalDateTime lastBeginDate = dateTime.minusMonths(1).with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
        dto.setLastBeginDate(formatterDateTime(lastBeginDate));

        // 上月结束时间
        LocalDateTime lastEndDate = dateTime.minusMonths(1).with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
        dto.setLastEndDate(formatterDateTime(lastEndDate));

        // 去年同月开始时间
        LocalDateTime lastYearBeginDate = dateTime.minusYears(1)
                .withMonth(dateTime.getMonthValue())
                .with(TemporalAdjusters.firstDayOfMonth())
                .with(LocalTime.MIN);
        dto.setLastYearBeginDate(formatterDateTime(lastYearBeginDate));

        // 去年同月结束时间
        LocalDateTime lastYearEndDate = dateTime.minusYears(1)
                .withMonth(dateTime.getMonthValue())
                .with(TemporalAdjusters.lastDayOfMonth())
                .with(LocalTime.MAX);
        dto.setLastYearEndDate(formatterDateTime(lastYearEndDate));

        // 本年开始时间
        LocalDateTime yearBeginDate = dateTime.with(TemporalAdjusters.firstDayOfYear()).with(LocalTime.MIN);
        dto.setYearBeginDate(formatterDateTime(yearBeginDate));

        // 本年结束时间
        LocalDateTime yearEndDate = dateTime.with(TemporalAdjusters.lastDayOfYear()).with(LocalTime.MAX);
        dto.setYearEndDate(formatterDateTime(yearEndDate));

        return dto;
    }

    /**
     * 格式化日期时间
     */
    private static String formatterDateTime(LocalDateTime dateTime) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        return dateTime.format(formatter);
    }

}
